home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / upc12bs1.zip / MAIL / mail.c < prev    next >
C/C++ Source or Header  |  1993-09-23  |  50KB  |  1,469 lines

  1. /*--------------------------------------------------------------------*/
  2. /*       m a i l . c                                                  */
  3. /*                                                                    */
  4. /*       Mailer User-Agent (UA)                                       */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*       Changes Copyright (c) 1989-1993 by Kendra Electronic         */
  9. /*       Wonderworks.                                                 */
  10. /*                                                                    */
  11. /*       All rights reserved except those explicitly granted by       */
  12. /*       the UUPC/extended license agreement.                         */
  13. /*--------------------------------------------------------------------*/
  14.  
  15. /*--------------------------------------------------------------------*/
  16. /*                          RCS Information                           */
  17. /*--------------------------------------------------------------------*/
  18.  
  19. /*
  20.  *    $Id: mail.c 1.8 1993/09/23 03:26:51 ahd Exp $
  21.  *
  22.  *    Revision history:
  23.  *    $Log: mail.c $
  24.  * Revision 1.8  1993/09/23  03:26:51  ahd
  25.  * Use current version variables for Visual C++ under Windows NT
  26.  *
  27.  * Revision 1.7  1993/09/20  04:39:51  ahd
  28.  * OS/2 2.x support
  29.  *
  30.  * Revision 1.6  1993/07/31  16:26:01  ahd
  31.  * Changes in support of Robert Denny's Windows support
  32.  *
  33.  * Revision 1.5  1993/07/24  03:40:55  ahd
  34.  * Change description of "-" command, previous command.
  35.  *
  36.  * version  1.0   Stuart Lynne
  37.  * version 1.5 Samuel Lam <skl@van-bc.UUCP>  August/87
  38.  *
  39.  * version 1.6 Drew Derbyshire   May/89
  40.  *             Support for single user aliases, -u option for reading
  41.  *             alternate mailboxes, parsing addresses via external routine,
  42.  *             parsing Resent- fields, suppressing Received: fields,
  43.  *             automatic positioning to next message.                   ahd
  44.  * 23 Sep 89   Version 1.07a
  45.  *             Support lists in aliases                                 ahd
  46.  *
  47.  * 29 Sep 89   Version 1.07b
  48.  *             Add prompting for subject in outgoing mail.              ahd
  49.  * 01 Oct 89   Add additional function prototypes to catch bad calls    ahd
  50.  * 02 Oct 89   Alter large strings/structures to use malloc()/free()    ahd
  51.  * 12 Oct 89   Version 1.07d
  52.  *             Correct free() of line in Send_Mail
  53.  * 12 Dec 89   Version 1.07g
  54.  *             Various spelling corrections
  55.  * 18 Mar 90   Version 1.07i
  56.  *             Add ~user support for save/write command
  57.  *             Add ignore list for user
  58.  *             Shorten lines printed by aborting from a print command   ahd
  59.  * 30 Apr  90  Add autoedit support for sending mail                    ahd
  60.  *  2 May  90  Add support for options= flags                           ahd
  61.  *  3 May  90  Split selected subroutines into maillib.c                ahd
  62.  *  4 May  90  Add 'save' option.                                       ahd
  63.  *  8 May  90  Add 'pager' option                                       ahd
  64.  * 10 May  90  Add 'purge' option                                       ahd
  65.  * 13 May  90  Alter logging so that no numbers are printed on console  ahd
  66.  * Additions for unofficial version 1.07k, Philip David Meese June 1990
  67.  * 16 June 90
  68.  *            -added mail command: Copy current (without delete)        pdm
  69.  *            -altered calls to Collect_Mail to support mail subcmds    pdm
  70.  *            -added handling of '+' to indicate "relative to home
  71.  *                directory" for BSD like mail users.                   pdm
  72.  * 12 Feb 91 rewrite parser a for more BSD like syntax
  73. */
  74.  
  75.  static const char rcsid[] =
  76.       "$Id: mail.c 1.8 1993/09/23 03:26:51 ahd Exp $";
  77.  
  78. /*--------------------------------------------------------------------*/
  79. /*                        System include files                        */
  80. /*--------------------------------------------------------------------*/
  81.  
  82. #include <ctype.h>
  83. #include <stdio.h>
  84. #include <io.h>
  85. #include <stdlib.h>
  86. #include <string.h>
  87. #include <limits.h>
  88. #include <time.h>
  89. #include <dos.h>
  90. #include <direct.h>
  91.  
  92. #ifdef _Windows
  93. #include <windows.h>
  94. #include <alloc.h>
  95. #endif
  96.  
  97. /*--------------------------------------------------------------------*/
  98. /*                    UUPC/extended include files                     */
  99. /*--------------------------------------------------------------------*/
  100.  
  101. #include "lib.h"
  102. #include "address.h"
  103. #include "alias.h"                                            /* ahd */
  104. #include "dater.h"
  105. #include "expath.h"
  106. #include "getopt.h"
  107. #include "hlib.h"
  108. #include "mail.h"
  109. #include "mailblib.h"
  110. #include "maillib.h"                                           /* ahd */
  111. #include "mailsend.h"
  112. #include "mlib.h"
  113. #include "pushpop.h"
  114. #include "stater.h"
  115. #include "timestmp.h"
  116.  
  117. #if defined(_Windows)
  118. #include "winutil.h"
  119. #endif
  120.  
  121. /*--------------------------------------------------------------------*/
  122. /*                          Global variables                          */
  123. /*--------------------------------------------------------------------*/
  124.  
  125. #ifdef _Windows
  126. unsigned _stklen = 10 * 1024;
  127. unsigned _heaplen = 30 * 1024;
  128. #endif
  129.  
  130. currentfile();
  131.  
  132. static char *tmailbox;
  133. static char mfilename[FILENAME_MAX];
  134. int letternum = 0;
  135.  
  136. static boolean useto = FALSE;
  137.  
  138. FILE *fmailbox;
  139.  
  140. #define MAXLETTERS   100
  141.  
  142. static int maxletters = MAXLETTERS;
  143.  
  144. struct  ldesc *letters;
  145.  
  146. /*--------------------------------------------------------------------*/
  147. /*                       Local procedure names                        */
  148. /*--------------------------------------------------------------------*/
  149.  
  150. static void    Cleanup(void);
  151.  
  152. static void Interactive_Mail( const boolean PrintOnly,
  153.                               const boolean postoffice );
  154.  
  155. static void    IncludeNew( const char *target, const char *user);
  156.  
  157. static void    PrintSubject(int msgnum, int letternum);
  158.  
  159. static void    UpdateMailbox(int letternum, boolean postoffice);
  160.  
  161. static int     CreateBox(FILE *rmailbox,
  162.                          FILE *fmailbox,
  163.                          const char *tmailbox);
  164.  
  165. static void usage( void );
  166.  
  167. /*--------------------------------------------------------------------*/
  168. /*                          Global variables                          */
  169. /*--------------------------------------------------------------------*/
  170.  
  171. static char *replytolist[] = { "Resent-Reply-To:",
  172.                         "Resent-From:",
  173.                         "Reply-To:",
  174.                         "From:",
  175.                          NULL };
  176.  
  177. static char *fromlist[] =    { "Resent-From:",
  178.                                "From:",
  179.                                NULL};
  180.  
  181. static char *tolist[] =    {   "Resent-To:",
  182.                                "To:",
  183.                                NULL};
  184.  
  185. static char *subjectlist[] = { "Resent-Subject:",
  186.                                "Subject:",
  187.                                 NULL };
  188.  
  189. static char *datelist[]  =   { "Resent-Date:",
  190.                                "Date:" ,
  191.                                NULL} ;
  192.  
  193.  
  194. /*--------------------------------------------------------------------*/
  195. /*                  Information on existing mailbox                   */
  196. /*--------------------------------------------------------------------*/
  197.  
  198. static long    mboxsize = 0;
  199. static time_t  mboxage  = 0;
  200.  
  201. /*--------------------------------------------------------------------*/
  202. /*                       Command parsing table                        */
  203. /*--------------------------------------------------------------------*/
  204.  
  205. #define NUMERIC_CMD "9999"
  206. #define EMPTY_CMD   ""
  207.  
  208. static struct CommandTable {
  209.    char *sym;
  210.    ACTION verb;
  211.    unsigned int bits;
  212.    char *help;
  213. } table[] = {
  214.  { EMPTY_CMD,     M_EMPTY,    NODISPLAY | NO_OPERANDS | AUTOPRINT ,
  215.          NULL},
  216.  { "!",           M_SYSTEM,   STRING_OP,
  217.          "Execute DOS command"},
  218.  { "+",           M_DOWN,     KEWSHORT_OP | AUTOPRINT,
  219.          "Alias for next"},
  220.  { "-",           M_UP,       KEWSHORT_OP | AUTOPRINT,
  221.          "Alias for previous"},
  222.  { "?",           M_FASTHELP, NO_OPERANDS,
  223.          "Print this help"},
  224.  { "alias",       M_ALIAS,    TOKEN_OP,
  225.          "Print user alias"},
  226.  { "copy",        M_COPY,     LETTER_OP | FILE_OP ,
  227.          "Copy item to file"},
  228.  { "delete",      M_DELETE,   LETTER_OP | POSITION | AUTOPRINT ,
  229.          "Delete mail item"},
  230.  { "debug",       M_DEBUG,    KEWSHORT_OP,
  231.          "Enable debug output"},
  232.  { "dquit",       M_DELETEQ,  LETTER_OP ,
  233.          "Delete then quit"},
  234.  { "exit",        M_EXIT,     NO_OPERANDS,
  235.          "Exit without updating mailbox"},
  236.  { "forward",     M_FORWARD,  LETTER_OP | USER_OP,
  237.          "Resend item to others"},
  238.  { "go",          M_GOTO,     LETTER_OP | AUTOPRINT ,
  239.          "Go to item"},
  240.  { "Headers",     M_HEADERS,  LETTER_OP | POSITION ,
  241.          "Print specified item summary"},
  242.  { "headers",     M_HEADERS,  NO_OPERANDS,
  243.          "Print all item summaries"},
  244.  { "help",        M_HELP,     NO_OPERANDS,
  245.          "Print long help text"},
  246.  { "mail",        M_MAIL,     USER_OP,
  247.          "Compose and send mail"},
  248.  { "next",        M_DOWN,     KEWSHORT_OP | AUTOPRINT ,
  249.          "Move to next item"},
  250.   {"print",       M_EXTPRINT, LETTER_OP | POSITION ,
  251.          "Print item (condensed)"},
  252.   {"Print",       M_INTPRINT, LETTER_OP | POSITION ,
  253.          "Print item (condensed)"},
  254.   {"previous",    M_UP,       KEWSHORT_OP | AUTOPRINT ,
  255.          "Move to previous item"},
  256.   {"quit",        M_QUIT,     NO_OPERANDS,
  257.          "Update mailbox, exit"},
  258.   {"reply",       M_REPLY,    LETTER_OP | POSITION ,
  259.          "Reply to sender of item"},
  260.   {"save",        M_SAVE,     LETTER_OP | FILE_OP | POSITION | AUTOPRINT ,
  261.          "Copy item, delete"},
  262.   {"set",         M_SET,      STRING_OP,
  263.          "Print/set boolean options"},
  264.   {"status",     M_STATUS,  NO_OPERANDS,
  265.          "Report version/status info"},
  266.   {"type",        M_EXTTYPE,  LETTER_OP | POSITION,
  267.          "Print item with all headers"},
  268.   {"Type",        M_INTTYPE,  LETTER_OP | POSITION,
  269.          "Print item with all headers"},
  270.   {"undelete",    M_UNDELETE, LETTER_OP | POSITION | AUTOPRINT ,
  271.          "Rescue item after save/delete"},
  272.   {"write",       M_WRITE,    LETTER_OP | FILE_OP | POSITION | AUTOPRINT ,
  273.          "Copy item w/o header, delete"},
  274.   {"xit",         M_EXIT,     NO_OPERANDS,
  275.          "alias for exit"},
  276.   { NUMERIC_CMD,   M_GOTO,     NODISPLAY | KEWSHORT_OP | AUTOPRINT ,
  277.          NULL} ,
  278.   { NULL,          M_INVALID,  NODISPLAY | STRING_OP,
  279.          NULL }
  280.          } ;
  281.  
  282. /*--------------------------------------------------------------------*/
  283. /*    m a i n                                                         */
  284. /*                                                                    */
  285. /*    Main program                                                    */
  286. /*--------------------------------------------------------------------*/
  287.  
  288. void main(int argc, char **argv)
  289. {
  290.  
  291.    boolean PrintOnly = FALSE;
  292.    boolean postoffice = TRUE;
  293.    boolean readmail   = FALSE;
  294.    boolean sendmail   = FALSE;
  295.    int option;
  296.    char    *subject = NULL;
  297.  
  298. #if defined(__CORE__)
  299.    copywrong = strdup(copyright);
  300.    checkref(copywrong);
  301. #endif
  302.  
  303.    banner( argv );
  304.  
  305.    if (!configure( B_MUA ))
  306.       exit(1);    /* system configuration failed */
  307.  
  308.    if (!InitRouter())
  309.       exit(1);    /* system configuration failed */
  310.  
  311.    tmailbox = mktempname(NULL, "TMP");
  312.    PushDir(".");
  313.  
  314. /*--------------------------------------------------------------------*/
  315. /*                       get mailbox file name                        */
  316. /*--------------------------------------------------------------------*/
  317.  
  318.    strcpy( mfilename, E_mailbox );
  319.    if ( strchr( mfilename ,'.' ) == NULL )
  320.       mfilename[8] = '\0';       /* Prevent OS/2 filename length
  321.                                     overrun                          */
  322.  
  323.    if ( bflag[ F_MULTITASK ] )
  324.    {
  325.       if (expand_path( mfilename, E_homedir, E_homedir, E_mailext ) == NULL )
  326.          panic();
  327.    }
  328.    else
  329.       mkmailbox(mfilename, E_mailbox );
  330.  
  331. /*--------------------------------------------------------------------*/
  332. /*                          parse arguments                           */
  333. /*--------------------------------------------------------------------*/
  334.  
  335.    while ((option = getopt(argc, argv, "f:ps:tu:x:")) != EOF)
  336.    {
  337.       char oname[FILENAME_MAX];
  338.  
  339.       switch (option)
  340.       {
  341.       case 'f':
  342.          readmail = TRUE;
  343.          strcpy( mfilename, optarg );
  344.          if (expand_path( mfilename, NULL, E_homedir, E_mailext ) == NULL )
  345.             usage();
  346.  
  347. /*--------------------------------------------------------------------*/
  348. /*    This next one is a little tricky ...  If we log outgoing        */
  349. /*    mail, we copy the name of the outgoing mail file into a         */
  350. /*    temporary buffer, and expand the name of the file to include    */
  351. /*    the path name.  If this name is the same as the current         */
  352. /*    file, flip-flip the useto flag which says use the To:           */
  353. /*    related fields when scanning headers, not the From:  related    */
  354. /*    fields.                                                         */
  355. /*--------------------------------------------------------------------*/
  356.  
  357.          if (( E_filesent != NULL ) &&
  358.              (expand_path( strcpy( oname, E_filesent) ,
  359.                           E_homedir, E_homedir , E_mailext ) != NULL ) &&
  360.              equali( oname , mfilename ))
  361.                            /* Our outgoing filename?              */
  362.             useto = ! useto;  /* Yes --> Automatically switch     */
  363.          postoffice = FALSE;
  364.          break;
  365.  
  366.       case 'p':
  367.          readmail = TRUE;
  368.          PrintOnly = TRUE;
  369.          break;
  370.  
  371.       case 'u':                  /* Read alternate mailbox?       */
  372.          readmail = TRUE;
  373.          mkmailbox(mfilename, optarg);
  374.          postoffice = FALSE;
  375.          break;
  376.  
  377.       case 'x':
  378.          debuglevel = atoi(optarg);
  379.          break;
  380.  
  381.       case 's':
  382.          sendmail = TRUE;
  383.          subject = optarg;
  384.          break;
  385.  
  386.       case 't':
  387.          readmail = TRUE;
  388.          useto = ! useto;
  389.          break;
  390.  
  391.       case '?':
  392.          usage();
  393.  
  394.       } /* switch */
  395.  
  396.    } /* while */
  397.  
  398. /*--------------------------------------------------------------------*/
  399. /*                        Check for conflicts                         */
  400. /*--------------------------------------------------------------------*/
  401.  
  402.    sendmail |= (optind != argc);
  403.  
  404.    if ( sendmail && readmail )
  405.    {
  406.       puts("Conflicting options specified");
  407.       usage();
  408.    }
  409.  
  410.    if ((optind == argc) && sendmail)
  411.    {
  412.       puts("Missing addresses for sending mail");
  413.       usage();
  414.    }
  415.  
  416. /*--------------------------------------------------------------------*/
  417. /*        We have the options, now decide how to process them         */
  418. /*--------------------------------------------------------------------*/
  419.  
  420.    if (sendmail)
  421.    {
  422.       argc -= optind;
  423.  
  424.       if ( subject != NULL )
  425.       {
  426.  
  427.          argv    = &argv[optind-2];
  428.          argv[0] = "-s";
  429.          argv[1] = subject;
  430.  
  431.          Collect_Mail(stdin, argc+2 , argv , -1, FALSE);
  432.       } /* if ( subject != NULL ) */
  433.       else {
  434.          Collect_Mail(stdin, argc, &argv[optind], -1, FALSE);
  435.  
  436. #ifdef _Windows
  437.          atexit ( CloseEasyWin );
  438. #endif
  439.       }
  440.  
  441.    } /* if (sendmail) */
  442.    else  {
  443.       if ( postoffice && bflag[ F_MULTITASK ] )
  444.          IncludeNew( mfilename, E_mailbox);
  445.       Interactive_Mail( PrintOnly , postoffice );
  446.    }
  447.  
  448.    Cleanup();
  449.    PopDir();
  450.    exit(0);
  451.  
  452. } /*main*/
  453.  
  454. /*--------------------------------------------------------------------*/
  455. /*    C l e a n u p                                                   */
  456. /*                                                                    */
  457. /*    Remove temporary files when exiting                             */
  458. /*--------------------------------------------------------------------*/
  459.  
  460. void Cleanup()
  461. {
  462.  
  463.    printmsg(2,"Deleting temporary mailbox %s", tmailbox);
  464.  
  465.    if ( fmailbox != NULL )
  466.    {
  467.       fclose(fmailbox);
  468.       fmailbox = NULL;
  469.    }
  470.  
  471.    unlink(tmailbox);
  472.  
  473. } /*Cleanup*/
  474.  
  475.  
  476. /*--------------------------------------------------------------------*/
  477. /*    I n t e r a c t i v e _ M a i l                                 */
  478. /*                                                                    */
  479. /*    main procedure for reading mail                                 */
  480. /*--------------------------------------------------------------------*/
  481.  
  482. static void Interactive_Mail( const boolean PrintOnly,
  483.                               const boolean postoffice )
  484. {
  485.    char resp[LSIZE];
  486.    int current = 0;                                               /* ahd   */
  487.    boolean done      = FALSE;                                     /* ahd   */
  488.    boolean modified;
  489.    FILE *rmailbox;
  490.  
  491. /*--------------------------------------------------------------------*/
  492. /*               Open real and temporary mailbox files                */
  493. /*--------------------------------------------------------------------*/
  494.  
  495.    if ((rmailbox = FOPEN(mfilename, "r",TEXT_MODE)) == nil(FILE)) {
  496.       printf("No mail in %s\n", mfilename);
  497.       return;
  498.    }
  499.  
  500.    mboxage = stater( mfilename, &mboxsize );
  501.                               /* Remember mailbox information        */
  502.  
  503.    if ((fmailbox = FOPEN(tmailbox, "w", BINARY_MODE)) == nil(FILE)) {
  504.       printerr(tmailbox);
  505.       return;
  506.    }
  507.  
  508.    letters = calloc(maxletters,sizeof(letters[0]));
  509.    checkref(letters);
  510.  
  511. /*--------------------------------------------------------------------*/
  512. /*                 Copy real mailbox to temporary one                 */
  513. /*--------------------------------------------------------------------*/
  514.  
  515.    setvbuf(rmailbox, NULL, _IOFBF, 8192);
  516.    setvbuf(fmailbox, NULL, _IOFBF, 8192);
  517.  
  518.    letternum = CreateBox(rmailbox, fmailbox, tmailbox);
  519.  
  520.    fclose(rmailbox);
  521.    fclose(fmailbox);
  522.  
  523.    rmailbox = fmailbox = NULL;
  524.  
  525.    if (letternum < 1)            /* Did we find any mail in the box? */
  526.    {                             /* No --> Return to caller          */
  527.       if (letternum == 0)
  528.          printf("No mail in %s\n", mfilename);
  529.       return;
  530.    }
  531.  
  532. /*--------------------------------------------------------------------*/
  533. /*        Shrink mailbox status array to what we actually need        */
  534. /*--------------------------------------------------------------------*/
  535.  
  536.    letters = realloc( letters, (letternum + 1) *  sizeof(letters[0]));
  537.    checkref(letters);
  538.  
  539.    fmailbox = FOPEN(tmailbox, "r", BINARY_MODE);
  540.  
  541.    if (fmailbox == NULL)
  542.    {
  543.       printerr(tmailbox);
  544.       panic();
  545.    } /* if */
  546.    setvbuf(fmailbox, NULL, _IOFBF, 8192);
  547.  
  548.    modified = postoffice && (!PrintOnly);
  549.  
  550.    if (PrintOnly) {
  551.       int j = 0;
  552.       while (j < letternum)
  553.       {
  554.          Pager(j, TRUE, noreceived, !j );
  555.          j++ ;
  556.       }
  557.       return;
  558.    }
  559.  
  560.    PrintSubject(-1,letternum); /* print all subjects */
  561.  
  562. /*--------------------------------------------------------------------*/
  563. /*               Determine first letter in to prompt at               */
  564. /*--------------------------------------------------------------------*/
  565.  
  566.       if (letternum == 0)
  567.          current = -1;
  568.       else
  569.          current = 0;
  570.  
  571. /*--------------------------------------------------------------------*/
  572. /*            Begin main command loop for reading the mail            */
  573. /*--------------------------------------------------------------------*/
  574.  
  575.    if (!bflag[F_EXPERT])
  576.       printf("Enter \"?\" for short help or \"help\" for long help.\n");
  577.  
  578. #ifdef _Windows
  579.    atexit ( CloseEasyWin );
  580. #endif
  581.  
  582.    while( ! done )
  583.    {
  584.       char *command, *operand;
  585.       int integer;
  586.       boolean first_pass = TRUE;
  587.       int previous = current;
  588.       struct CommandTable *cmd_ptr = table;
  589.       boolean success = TRUE;
  590.       boolean crlf    = FALSE;      /* crlf after delete command?    */
  591.  
  592.       printf("%d%s",current + 1,
  593.                (letters[current].status == M_DELETED) ? "*" : " ");
  594.       if (!Console_fgets(resp, LSIZE, "? ")) /* End of file?         */
  595.       {
  596.          done = TRUE;
  597.          continue;            /* Yes --> Exit loop                   */
  598.       }
  599.       PageReset();
  600.  
  601. /*--------------------------------------------------------------------*/
  602. /*                     Locate command to execute                      */
  603. /*--------------------------------------------------------------------*/
  604.  
  605.       integer = strlen( resp );
  606.       if (integer && ( resp[ integer - 1 ] == '\n'))
  607.          resp[ integer - 1 ] = '\0';   /* Trim newline, if any       */
  608.  
  609.       operand = command = strtok( resp, WHITESPACE );
  610.       if ( command == NULL )
  611.          command = EMPTY_CMD;
  612.       else if (Numeric(command))
  613.          command = NUMERIC_CMD;
  614.  
  615.       while( cmd_ptr->sym != NULL)
  616.       {
  617.          if (equaln(command, cmd_ptr->sym, strlen(command)))
  618.             break;            /* Exit if we have a hit               */
  619.          cmd_ptr++;           /* Examine next command                */
  620.       } /* while */
  621.  
  622. /*--------------------------------------------------------------------*/
  623. /*     Get rest of command line, and trim leading spaces from it      */
  624. /*--------------------------------------------------------------------*/
  625.  
  626.       if (!equal(command, NUMERIC_CMD) && (operand != NULL))
  627.       {
  628.          operand = strtok( NULL , "");
  629.                               /* Save rest of string for later       */
  630.          if ( operand != NULL )
  631.          {
  632.             while( isspace( *operand ))
  633.                operand++ ;
  634.  
  635.             if (*operand == '\0')
  636.                operand = NULL ;
  637.          } /* if */
  638.       }
  639.  
  640. /*--------------------------------------------------------------------*/
  641. /*        Parse items to be selected from mailbox for command         */
  642. /*--------------------------------------------------------------------*/
  643.  
  644.       if (cmd_ptr->bits & (LETTER_OP) )
  645.          success = SelectItems( &operand, current, cmd_ptr->bits);
  646.  
  647. /*--------------------------------------------------------------------*/
  648. /*                  Process the operands in the list                  */
  649. /*--------------------------------------------------------------------*/
  650.  
  651.       while( success &&
  652.              Get_Operand( &integer, &operand, cmd_ptr->bits, first_pass) )
  653.       {
  654.          switch( cmd_ptr->verb )
  655.          {
  656.             case M_ALIAS:
  657.                ShowAlias( operand );
  658.                break;
  659.  
  660.             case M_COPY:
  661.                success = SaveItem( integer,
  662.                          FALSE,        /* Do not delete */
  663.                          seperators,   /* Do save headers */
  664.                          (operand == NULL) ? "PRN" : operand ,
  665.                          cmd_ptr->verb );
  666.                break;
  667.  
  668.             case M_DEBUG:
  669.                debuglevel = integer;
  670.                printmsg(0,"Debug set to %d",debuglevel);
  671.                break;
  672.  
  673.             case M_DELETEQ:
  674.                done = TRUE;
  675.             case M_DELETE:
  676.                if (letters[integer].status < M_DELETED)
  677.                {
  678.                   letters[integer].status = M_DELETED;
  679.                   if ( ! crlf )
  680.                      printf("Deleting item(s) %d",integer + 1 );
  681.                   else
  682.                      printf(" %d",integer + 1 );
  683.                   crlf  = modified = TRUE;
  684.                }
  685.                break;
  686.  
  687.             case M_DOWN:
  688.                current = Position( 0 , integer , current );
  689.                break;
  690.  
  691.             case M_EMPTY:
  692.                if ( bflag[F_DOSKEY] && !bflag[F_EXPERT] )
  693.                {
  694.                   printf("DOSKEY active, empty line ignored\n");
  695.                   PrintSubject( current , letternum );
  696.                   success = FALSE;
  697.                }
  698.                else if (letters[current].status == M_UNREAD)
  699.                   success = Pager( current , TRUE, noreceived, first_pass);
  700.                else
  701.                   current = Position( 0 , 1 , current );
  702.                break;
  703.  
  704.             case M_EXIT:
  705.                modified = FALSE;
  706.                done     = TRUE;
  707.                break;
  708.  
  709.             case M_EXTPRINT:
  710.                success = Pager( integer , TRUE, noreceived, first_pass);
  711.                break;
  712.  
  713.             case M_EXTTYPE:
  714.                success = Pager( integer , TRUE, noseperator, first_pass);
  715.                break;
  716.  
  717.             case M_FASTHELP:
  718.             {
  719.                size_t subscript = 0;
  720. #ifndef _Windows
  721.                size_t column    = 0;
  722. #endif
  723.                fputs("Valid commands are:\n",stdout);
  724.                while( table[subscript].sym != NULL)
  725.                {
  726.                   if ( !(table[subscript].bits & NODISPLAY ))
  727.                   {
  728. #ifdef _Windows
  729.                      fputc( '\n' , stdout );
  730. #else
  731.                      fputc( ( column++ % 2 ) ? ' ' : '\n' , stdout );
  732. #endif
  733.                      printf("%-9s%-30s",table[subscript].sym,
  734.                                        table[subscript].help );
  735.                   } /* if */
  736.                   subscript ++;
  737.                } /* while */
  738.                fputs("\n\nEnter \"help\" for additional information.\n",
  739.                         stdout);
  740.                break;
  741.             } /* case */
  742.  
  743.             case M_FORWARD:
  744.                success = ForwardItem( integer, operand);
  745.                break;
  746.  
  747.             case M_GOTO:
  748.                current = Position( integer, 0, current );
  749.                break;
  750.  
  751.             case M_HEADERS:
  752.                PrintSubject( (cmd_ptr->bits & NO_OPERANDS) ?
  753.                                  -1 : integer, letternum );
  754.                break;
  755.  
  756.             case M_HELP:
  757.             {
  758.                char filename[FILENAME_MAX];
  759.                mkfilename(filename, E_confdir, "mail.hlp");
  760.                Sub_Pager(filename, TRUE );
  761.                break;
  762.             }
  763.  
  764.             case M_INTPRINT:
  765.                success = Pager( integer , FALSE, noreceived, first_pass);
  766.                break;
  767.  
  768.             case M_INTTYPE:
  769.                success = Pager( integer , FALSE, noseperator, first_pass);
  770.                break;
  771.  
  772.             case M_INVALID:
  773.                printf("Invalid command \"%s\".  Enter \"?\" for help.\n",
  774.                         command);
  775.                break;
  776.  
  777.             case M_MAIL:
  778.                success = DeliverMail( operand , current);
  779.                break;
  780.  
  781.             case M_NOOP:
  782.                break;
  783.  
  784.             case M_REPLY:
  785.                success = Reply( integer );
  786.                break;
  787.  
  788.             case M_QUIT:
  789.                done = TRUE;
  790.                break;
  791.  
  792.             case M_SAVE:
  793.                success = SaveItem( integer,
  794.                          TRUE,         /* Do delete */
  795.                          seperators,   /* Do save headers */
  796.                          operand ,
  797.                          cmd_ptr->verb );
  798.                modified = TRUE;
  799.                break;
  800.  
  801.             case M_SET:
  802.                if (operand == NULL)
  803.                   sayoptions( configFlags);
  804.                else
  805.                   options(operand, USER_CONFIG, configFlags, bflag);
  806.                break;
  807.  
  808.             case M_SYSTEM:
  809.                subshell( operand );
  810.                break;
  811.  
  812.             case M_UNDELETE:
  813.                letters[integer].status = M_UNREAD;
  814.                break;
  815.  
  816.             case M_UP:
  817.                current = Position( 0 , - integer , current );
  818.                break;
  819.  
  820.             case M_STATUS:
  821.                printf("%s:\t%s created %s %s running under %s %d.%02d\n",
  822.                        compilep, compilev, compiled, compilet,
  823.  
  824. #ifdef WIN32
  825.                      "Windows NT",
  826.                      _winmajor,
  827.                      _winminor);
  828. #elif defined(__OS2__)
  829.                     "OS/2(R)" ,
  830.                     (int) _osmajor / 10,
  831.                       _osminor);
  832. #elif defined(__TURBOC__)
  833.                     "DOS",
  834.                     _osmajor,
  835.                     _osminor);
  836. #else
  837.                     (_osmode == DOS_MODE) ? "DOS" : "OS/2(R)" ,
  838.                     (_osmode == DOS_MODE) ? _osmajor : ((int) _osmajor / 10 ),
  839.                      _osminor);
  840. #endif
  841. #ifdef _Windows
  842.                printf("Windows version: %s\t", compilew );
  843. #endif
  844.                printf("Magic Word:\t%s\n","flarp");
  845.                printf("Return address:\t\"%s\" <%s@%s>\n"
  846.                       "Domain name:\t%s\tNodename:\t%s\n",
  847.                         E_name, E_mailbox, E_fdomain, E_domain, E_nodename );
  848.                printf("Current File:\t%s\tNumber of items: %d\n"
  849.                       "File size:\t%ld bytes\tLast updated:\t%s",
  850.                         mfilename, letternum + 1 , mboxsize ,
  851.                         ctime( & mboxage ) );
  852.                break;
  853.  
  854.             case M_WRITE:
  855.                success = SaveItem( integer,
  856.                          TRUE,      /* Do delete */
  857.                          noheader,  /* Do not save headers */
  858.                          operand,
  859.                          cmd_ptr->verb );
  860.                modified = TRUE;
  861.          } /* switch */
  862.          first_pass = FALSE;
  863.       } /* while */
  864.  
  865.       success = ! first_pass; /* If first_pass not run, then
  866.                                  Get_Operand failed                  */
  867.  
  868.       if ( crlf )
  869.          putchar('\n');
  870.  
  871.       if ( success && !done )
  872.       {
  873.          if (cmd_ptr->bits & POSITION)
  874.             current = Position( 0 , 0 , integer );
  875.  
  876.          if ( current != previous )
  877.          {
  878.             if ( (cmd_ptr->bits & AUTOPRINT ) &&
  879.                   bflag[F_AUTOPRINT] &&
  880.                   (letters[current].status != M_DELETED) )
  881.                Pager( current , TRUE, noreceived, TRUE);
  882.             else
  883.                PrintSubject( current , letternum );
  884.          } /* if */
  885.       } /* if */
  886.    } /* while */
  887.  
  888. /*--------------------------------------------------------------------*/
  889. /*                       End main command loop                        */
  890. /*--------------------------------------------------------------------*/
  891.  
  892.    if (modified)
  893.       UpdateMailbox(letternum, postoffice);
  894.  
  895.    free(letters);
  896.  
  897. } /*Interactive_Mail*/
  898.  
  899. /*--------------------------------------------------------------------*/
  900. /*    I n c l u d e N e w                                             */
  901. /*                                                                    */
  902. /*    Includes mail from the system box into the user's local         */
  903. /*    mailbox                                                         */
  904. /*--------------------------------------------------------------------*/
  905.  
  906. static void IncludeNew( const char *target, const char *user)
  907. {
  908.    long age, size;
  909.    FILE *stream_in;
  910.    FILE *stream_out;
  911.    int  bytes;
  912.  
  913.    char sysbox[FILENAME_MAX];
  914.    char buf[BUFSIZ];
  915.  
  916.    mkmailbox(sysbox, user);
  917.  
  918. /*--------------------------------------------------------------------*/
  919. /*      Return semi-quietly if we can't open the system mailbox       */
  920. /*--------------------------------------------------------------------*/
  921.  
  922.    stream_in   = FOPEN( sysbox, "r", BINARY_MODE);
  923.    if ( stream_in == NULL )
  924.    {
  925.       if ( debuglevel > 1 )
  926.          printerr( sysbox );
  927.       return;
  928.    }
  929.  
  930. /*--------------------------------------------------------------------*/
  931. /*      Determine if we have new mail, returning quietly if not       */
  932. /*--------------------------------------------------------------------*/
  933.  
  934.    age = stater( sysbox , &size );
  935.  
  936.    if ( age == -1)
  937.       panic();
  938.  
  939.    printmsg( 1, "Including mail from %s through %s",
  940.             sysbox,
  941.             ctime(&age));
  942.  
  943. /*--------------------------------------------------------------------*/
  944. /*                    Now open up the output file                     */
  945. /*--------------------------------------------------------------------*/
  946.  
  947.    stream_out  = FOPEN( target, "a+", BINARY_MODE);
  948.  
  949.    if ( stream_out == NULL )
  950.    {
  951.       printerr( target );
  952.       panic();
  953.    }
  954.  
  955. /*--------------------------------------------------------------------*/
  956. /*                       Loop to read the data                        */
  957. /*--------------------------------------------------------------------*/
  958.  
  959.    while ((bytes = fread(buf,sizeof(char), sizeof buf, stream_in)) > 0)
  960.    {
  961.       if ((int) fwrite(buf, sizeof(char), bytes, stream_out) != bytes)
  962.       {
  963.          printmsg(0, "Error including new mail into %s", target );
  964.          printerr( target );
  965.          fclose( stream_in );
  966.          fclose( stream_out );
  967.          panic();
  968.       }
  969.    } /* while */
  970.  
  971. /*--------------------------------------------------------------------*/
  972. /*                   Clean up and return to caller                    */
  973. /*--------------------------------------------------------------------*/
  974.  
  975.    if ( ferror( stream_in ))
  976.    {
  977.       printerr( sysbox );
  978.       panic();
  979.    }
  980.  
  981.    fclose( stream_in  );
  982.    fclose( stream_out );
  983.  
  984.    filebkup( sysbox );
  985.    unlink(sysbox);
  986.  
  987. } /* IncludeNew */
  988.  
  989. /*--------------------------------------------------------------------*/
  990. /*    C r e a t e B o x                                               */
  991. /*                                                                    */
  992. /*    Creates the temporary mailbox and related tables                */
  993. /*--------------------------------------------------------------------*/
  994.  
  995. int CreateBox(FILE *rmailbox, FILE *fmailbox , const char *tmailbox)
  996. {
  997.  
  998. /*--------------------------------------------------------------------*/
  999. /*          Copy real mailbox file to temporary mailbox file          */
  1000. /*--------------------------------------------------------------------*/
  1001.  
  1002.    int letternum = 0;
  1003.    boolean inheader = FALSE;
  1004.    long position;
  1005.    char line[LSIZE];
  1006.    char **list;
  1007.    size_t replyprior = 0;
  1008.    size_t dateprior = 0;
  1009.    size_t subjectprior = 0;
  1010.    size_t fromprior = 0;
  1011.  
  1012.    struct ldesc *letter = NULL;
  1013.  
  1014.    while ((fgets(line, LSIZE, rmailbox) != nil(char)) ){
  1015.  
  1016.       if (inheader)
  1017.       {
  1018.          if (*line == '\n')
  1019.             inheader = FALSE;
  1020.       }  /* inheader */
  1021.       else {               /* Determine if starting new message   */
  1022.          if (equal(line,MESSAGESEP) ||
  1023.             (bflag[F_FROMSEP] && equaln(line, "From ", 5)))
  1024.          {
  1025.              while (equal(line,MESSAGESEP))
  1026.              if (fgets(line, LSIZE, rmailbox) == NULL)
  1027.              {
  1028.                printerr(mfilename);
  1029.                panic();
  1030.              } /* if */
  1031.  
  1032. /*--------------------------------------------------------------------*/
  1033. /*               Make the mailbox bigger if we need to                */
  1034. /*--------------------------------------------------------------------*/
  1035.  
  1036.              position = ftell(fmailbox);
  1037.              if ( (letternum+1) == maxletters )
  1038.              {
  1039.                maxletters = max((int) ((maxletters * mboxsize) / position),
  1040.                                  (letternum * 11) / 10 );
  1041.                printmsg(2,"Reallocating mailbox array from %d to %d entries",
  1042.                      letternum+1, maxletters );
  1043.                letters = realloc( letters, maxletters *  sizeof(letters[0]));
  1044.                checkref( letters );
  1045.              }
  1046.  
  1047. /*--------------------------------------------------------------------*/
  1048. /*             Initialize this entry in th mailbox array              */
  1049. /*--------------------------------------------------------------------*/
  1050.  
  1051.              letter = &letters[letternum++];
  1052.  
  1053.              fromprior = subjectprior = replyprior = dateprior = INT_MAX;
  1054.              letter->from = letter->subject = letter->date =
  1055.                   letter->replyto = MISSING;
  1056.              letter->adr = position;
  1057.              letter->status = M_UNREAD;
  1058.              letter->lines = 0L;
  1059.              inheader = TRUE;
  1060.              printf("Reading message %d (%d%% done)\r",letternum,
  1061.                         (int) (position * 100 / mboxsize));
  1062.          }
  1063.          else
  1064.          {
  1065.             if(letter == NULL)   /* Did we find first letter?     */
  1066.             {                    /* No --> Abort with message     */
  1067.                fprintf(stderr,"%s  %s\n\a",
  1068.                   "This mailbox is not in UUPC/extended format!",
  1069.                   bflag[F_FROMSEP] ?
  1070.                   "Messages must be seperated by From lines!" :
  1071.                   "(Try \"options=fromsep\" in your configuration file)");
  1072.                panic();
  1073.             } /* if */
  1074.  
  1075.             letter->lines++;
  1076.          } /* else */
  1077.       } /* else */
  1078.  
  1079.       if (inheader)
  1080.       {
  1081.          size_t priority = 0;
  1082.  
  1083. /*--------------------------------------------------------------------*/
  1084. /*              Search for the best Date: related field               */
  1085. /*--------------------------------------------------------------------*/
  1086.  
  1087.          while ( (dateprior > priority) && (datelist[priority] != NULL ))
  1088.          {
  1089.             if (equalni(line, datelist[priority],
  1090.                              strlen(datelist[priority]) ) )
  1091.             {
  1092.                letter->date = ftell(fmailbox);
  1093.                dateprior = priority;
  1094.             }
  1095.             priority++;
  1096.          }
  1097.  
  1098. /*--------------------------------------------------------------------*/
  1099. /*             Search for the best Subject: related field             */
  1100. /*--------------------------------------------------------------------*/
  1101.  
  1102.          priority = 0;
  1103.          while ( (subjectprior > priority) &&
  1104.                  (subjectlist[priority] != NULL ))
  1105.          {
  1106.             if (equalni(line, subjectlist[priority],
  1107.                              strlen(subjectlist[priority]) ) )
  1108.             {
  1109.                letter->subject = ftell(fmailbox);
  1110.                subjectprior = priority;
  1111.             }
  1112.             priority++;
  1113.          }
  1114.  
  1115. /*--------------------------------------------------------------------*/
  1116. /*           Search for the best From: header related field           */
  1117. /*--------------------------------------------------------------------*/
  1118.  
  1119.          list = (useto) ? tolist : fromlist;
  1120.          priority = 0;
  1121.          while ( (fromprior > priority) && (list[priority] != NULL ))
  1122.          {
  1123.             if (equalni(line, list[priority],
  1124.                              strlen(list[priority]) ) )
  1125.             {
  1126.                letter->from = ftell(fmailbox);
  1127.                fromprior = priority;
  1128.             }
  1129.             priority++;
  1130.          } /* while */
  1131.  
  1132. /*--------------------------------------------------------------------*/
  1133. /*             Search for the best Reply-To related field             */
  1134. /*--------------------------------------------------------------------*/
  1135.  
  1136.          priority = 0;
  1137.          while ( (replyprior > priority) &&
  1138.                  (replytolist[priority] != NULL ))
  1139.          {
  1140.             if (equalni(line, replytolist[priority],
  1141.                              strlen(replytolist[priority]) ) )
  1142.             {
  1143.                letter->replyto = ftell(fmailbox);
  1144.                replyprior = priority;
  1145.             } /* if */
  1146.             priority++;
  1147.          }  /* while */
  1148.       } /* inheader */
  1149.  
  1150.       if (fputs(line, fmailbox) == EOF )
  1151.       {
  1152.          printerr(tmailbox);
  1153.          panic();
  1154.       } /* if */
  1155.  
  1156.  
  1157.    } /* while */
  1158.  
  1159.    letters[letternum].adr = ftell(fmailbox);
  1160.    letters[letternum].status = M_DELETED;
  1161.  
  1162.  
  1163.    fclose(rmailbox);
  1164.    fclose(fmailbox);
  1165.  
  1166.    return letternum;
  1167.  
  1168. } /* CreateBox */
  1169.  
  1170. /*--------------------------------------------------------------------*/
  1171. /*    P r i n t S u j e c t                                           */
  1172. /*                                                                    */
  1173. /*    Print the subject line of one or all messages in the mailbox    */
  1174. /*--------------------------------------------------------------------*/
  1175.  
  1176. void PrintSubject(int msgnum,int letternum)
  1177. {
  1178.    struct ldesc *ld;
  1179.    char from[LSIZE];
  1180.    char subject[LSIZE];
  1181.    char date[LSIZE];
  1182.    char line[LSIZE];
  1183.  
  1184.    int k, mink, maxk;
  1185.  
  1186.    if (msgnum == -1)
  1187.    {                                         /* print all of them? */
  1188.       sprintf(line," %d messages in file %s.\n",letternum,mfilename);
  1189.       PageLine(line);
  1190.       mink = 0;
  1191.       maxk = letternum - 1;
  1192.    } else
  1193.       mink = maxk = msgnum;
  1194.  
  1195.    for (k = mink ; k <= maxk ; k++) {
  1196.  
  1197.       ld = &letters[k];
  1198.       if ((ld->status == M_DELETED) && (msgnum == -1))
  1199.          continue;
  1200.  
  1201.       ReturnAddress(from,ld);       /* Get return address for letter */
  1202.  
  1203.       /* Date: Wed May 13 23:59:53 1987 */
  1204.       *date = '\0';  /* default date to null */
  1205.       if (RetrieveLine(ld->date, date, LSIZE)) {
  1206.          sscanf(date, "%*s %*s %s %s", line, subject);
  1207.          sprintf(date, "%s %s", line, subject);
  1208.       }
  1209.  
  1210.       strcpy(subject, "--- no subject ---");
  1211.       if (RetrieveLine(ld->subject, line, LSIZE)) {
  1212.          register char  *sp;
  1213.          sp = line;
  1214.          while (!isspace(*sp))
  1215.             sp++;
  1216.          while (isspace(*sp))
  1217.             sp++;
  1218.          strcpy(subject, sp);
  1219.       }
  1220.  
  1221.       /* make sure the fields aren't too long */
  1222.  
  1223.       from[25] = '\0';
  1224.       date[6] = '\0';
  1225.       subject[30] = '\0';
  1226.  
  1227.       sprintf(line, "%3d%c %6s  %-25s  %-30s  (%5ld)\n", k + 1,
  1228.          ((ld->status == M_DELETED) ? '*' : ' '),
  1229.             date, from, subject, ld->lines);
  1230.  
  1231.       if (PageLine(line))
  1232.          break;
  1233.  
  1234.    }
  1235.  
  1236. } /*PrintSubject*/
  1237.  
  1238.  
  1239. /*--------------------------------------------------------------------*/
  1240. /*    U p d a t e  M a i l b o x                                      */
  1241. /*                                                                    */
  1242. /*    Update the permanent mailbox for the user                       */
  1243. /*--------------------------------------------------------------------*/
  1244.  
  1245. void UpdateMailbox(int letternum, boolean postoffice)
  1246. {
  1247.    int current;
  1248.    boolean changed = FALSE;
  1249.    boolean problem = FALSE;
  1250.    FILE *fmailbag;
  1251.    FILE *mbox = NULL;
  1252.    char *mboxname = NULL;
  1253.    long newsize;
  1254.    time_t newage;
  1255.    size_t msave = 0;
  1256.    size_t psave = 0;
  1257.  
  1258. /*--------------------------------------------------------------------*/
  1259. /*    Auto save into user's home directory mailbox if we were         */
  1260. /*    reading the system mailbox and the user specified the           */
  1261. /*    'save' option.                                                  */
  1262. /*--------------------------------------------------------------------*/
  1263.  
  1264.    postoffice = postoffice && bflag[F_SAVE];
  1265.  
  1266. /*--------------------------------------------------------------------*/
  1267. /*     Determine if anything was actually changed in the mailbox      */
  1268. /*--------------------------------------------------------------------*/
  1269.  
  1270.    for (current = 0;
  1271.         (current < letternum) && (! changed);
  1272.         current++)
  1273.    {
  1274.       if (letters[current].status == M_DELETED)
  1275.          changed = TRUE;
  1276.  
  1277.       if (postoffice && (letters[current].status != M_UNREAD))
  1278.          changed = TRUE;
  1279.    }
  1280.  
  1281.    if (!changed)
  1282.       return;
  1283.  
  1284. /*--------------------------------------------------------------------*/
  1285. /*    Determine if the mailbox has changed since we built our         */
  1286. /*    temporary file                                                  */
  1287. /*--------------------------------------------------------------------*/
  1288.  
  1289.    newage = stater( mfilename , &newsize );
  1290.  
  1291.    if ( mboxsize != newsize )
  1292.    {
  1293.       printf("%s size has changed from %ld to %ld bytes\n",
  1294.             mfilename, mboxsize, newsize );
  1295.       problem = TRUE;
  1296.    }
  1297.  
  1298.    if ( mboxage != newage )
  1299.    {
  1300.       char mboxbuf[DATEBUF];
  1301.       char newbuf[DATEBUF];
  1302.       printf("%s date stamp has changed from %s to %s\n",
  1303.             mfilename, dater(mboxage, mboxbuf), dater(newage, newbuf) );
  1304.       problem = TRUE;
  1305.    }
  1306.  
  1307.    while ( problem )
  1308.    {
  1309.       int c;
  1310.  
  1311.       printf("WARNING! File %s has changed, data may be lost if updated!\n",
  1312.             mfilename);
  1313.       fputs("Update anyway? ",stdout);
  1314.  
  1315.       c     = Get_One();
  1316.  
  1317.       switch (tolower( c ))
  1318.       {
  1319.          case 'y':
  1320.             puts("Yes");
  1321.             problem = FALSE;
  1322.             break;
  1323.  
  1324.          case 'n':
  1325.             printf("No\nUpdate aborted, %s left unchanged.\n",
  1326.                      mfilename);
  1327.             return;
  1328.  
  1329.          default:
  1330.             printf("%c - Invalid Response\n",c);
  1331.             break;
  1332.       } /* switch */
  1333.    } /* while ( problem ) */
  1334.  
  1335. /*--------------------------------------------------------------------*/
  1336. /*                Allocate auto save related variables                */
  1337. /*--------------------------------------------------------------------*/
  1338.  
  1339.    if (postoffice)
  1340.    {
  1341.       mboxname = malloc(FILENAME_MAX);
  1342.       checkref(mboxname);
  1343.       strcpy( mboxname, "mbox" );
  1344.       expand_path( mboxname, E_homedir, E_homedir, E_mailext );
  1345.    } /* if (postoffice) */
  1346.  
  1347. /*--------------------------------------------------------------------*/
  1348. /*                   Create a backup file if needed                   */
  1349. /*--------------------------------------------------------------------*/
  1350.  
  1351.    if ( bflag[F_BACKUP] )
  1352.       filebkup( mfilename );
  1353.  
  1354. /*--------------------------------------------------------------------*/
  1355. /*                    Begin re-writing the mailbox                    */
  1356. /*--------------------------------------------------------------------*/
  1357.  
  1358.    if ((fmailbag = FOPEN(mfilename, "w",TEXT_MODE)) == nil(FILE))
  1359.    {
  1360.       printf("UpdateMailbox: can't rewrite %s.\n", mfilename);
  1361.       Cleanup();
  1362.    } /* if */
  1363.  
  1364.    setvbuf(fmailbag, NULL, _IOFBF, 8192);
  1365.  
  1366. /*--------------------------------------------------------------------*/
  1367. /*    We got the files open, now actually loop through copying        */
  1368. /*    data from our temporary mailbox back into the permenent one,    */
  1369. /*    or in the user's mbox if he read the message and the post       */
  1370. /*    office is open.                                                 */
  1371. /*--------------------------------------------------------------------*/
  1372.  
  1373.    printf("Cleaning up ", current+ 1);
  1374.  
  1375.    for (current = 0; current < letternum;  current++)
  1376.    {
  1377.       if (letters[current].status == M_DELETED)
  1378.       {
  1379.          /* No operation */
  1380.          fputc('.', stdout);
  1381.       }
  1382.       else if (postoffice && (letters[current].status != M_UNREAD))
  1383.       {
  1384.  
  1385.          if ( mbox == NULL )  /* Mailbox already open?               */
  1386.          {                    /* No --> Do so now                    */
  1387.             mbox = FOPEN(mboxname, "a",TEXT_MODE);
  1388.             if (mbox == NULL) /* Open fail?                          */
  1389.             {                  /* Yes --> Disable postoffice autosave*/
  1390.                printf("\nUpdateMailbox: can't append to %s.\n", mboxname);
  1391.                postoffice = FALSE;
  1392.                current--;     /* Process this entry again            */
  1393.             } /* if */
  1394.             else
  1395.                setvbuf(mbox, NULL, _IOFBF, 8192);
  1396.          } /* if ( mbox == NULL ) */
  1397.  
  1398.          if ( mbox != NULL )
  1399.          {
  1400.             fputc('+', stdout);
  1401.             CopyMsg(current, mbox, seperators, FALSE);
  1402.             msave++;
  1403.          } /* mbox */
  1404.       }
  1405.       else {
  1406.          fputc('*', stdout);
  1407.          CopyMsg(current, fmailbag, seperators, FALSE);
  1408.          psave ++;
  1409.       } /* else */
  1410.  
  1411.    } /* for */
  1412.    fputs(" done!\n", stdout);
  1413.  
  1414. /*--------------------------------------------------------------------*/
  1415. /*    Close the post office.  We close the 'mbox' in the user's       */
  1416. /*    home directory, report if any data was saved in it, and         */
  1417. /*    then free the storage associated with the postoffice processing.*/
  1418. /*--------------------------------------------------------------------*/
  1419.  
  1420.    if ( postoffice )
  1421.    {
  1422.  
  1423.       if (msave > 0)          /* Did we write data into mailbox?  */
  1424.       {                       /* Yes --> Report it                */
  1425.          fclose(mbox);
  1426.          printf("%d letter%s saved in %s%s",
  1427.                msave,
  1428.                (msave > 1) ? "s" : "" ,
  1429.                mboxname,
  1430.                (psave > 0) ? ", " : ".\n");
  1431.       }
  1432.  
  1433.       free(mboxname);
  1434.    } /* if (postoffice) */
  1435.  
  1436. /*--------------------------------------------------------------------*/
  1437. /*    Now, clean up after the input mailbox.  We close it, and        */
  1438. /*    report when anything was saved into it.  If nothing was         */
  1439. /*    saved, we delete the file if the 'purge' option is active.      */
  1440. /*--------------------------------------------------------------------*/
  1441.  
  1442.    fclose(fmailbag);
  1443.  
  1444.    if (psave > 0)
  1445.       printf("%d letter%s held in %s.\n",
  1446.             psave ,
  1447.             (psave > 1) ? "s" : "" , mfilename);
  1448.    else if (bflag[F_PURGE] )
  1449.    {
  1450.       remove(mfilename);
  1451.       printf("Empty mail box %s has been deleted.\n", mfilename);
  1452.    }
  1453.  
  1454. } /* UpdateMailbox */
  1455.  
  1456. /*--------------------------------------------------------------------*/
  1457. /*    U s a g e                                                       */
  1458. /*                                                                    */
  1459. /*    Report command line syntax                                      */
  1460. /*--------------------------------------------------------------------*/
  1461.  
  1462. static void usage( void )
  1463. {
  1464.    puts("\nUsage:\tmail [-s subject] recipient ... "
  1465.          "[-c recipient ...] [-b receipient ...]\n"
  1466.          "\tmail [-f mailbox] [-u user] [-t] [-p] [-x debug]");
  1467.    exit(1);
  1468. }
  1469.